#ifndef _HASHING_STRATEGY_
#define _HASHING_STRATEGY_

#include <stdint.h>
#include <iostream>
#include <string>

class HashingStrategy {

    private:

        enum HashSTM { PROCESSING, CORRUPTED, FINISHED };
        HashSTM stm;

        uint8_t* digest;
        size_t digest_length;

    protected:

        HashingStrategy(size_t hash_length);

        void next_state(void);
        void set_corrupted(void);
        bool is_corrupted(void) const;
        bool final_state(void) const;
        void set_digest(uint8_t* array, size_t length);

        /* Circular left shift of x of n bits.
        **/
        static inline uint32_t rotate_left( uint32_t x, unsigned int n );

    public:

        virtual ~HashingStrategy();

        /*
         * \brief Process a byte array of a given length in the hashing context
         **/
        virtual void process(const uint8_t *array, size_t length) = 0;
        virtual void finalize(void) = 0;

        void get_digest(uint8_t* array, size_t length) const;
        std::string to_string(void) const;

};

/* Circular left shift of x of n bits.
 **/
inline uint32_t HashingStrategy::rotate_left( uint32_t x, unsigned int n )
{
    return (x << n) | (x >> (32 - n));
}

std::ostream& operator<< (std::ostream& os, const HashingStrategy &h);

#endif
